package cn.iocoder.yudao.module.reading.service.community;

import cn.hutool.core.collection.CollUtil;
import cn.iocoder.yudao.module.reading.dal.dataobject.community.CommunityCommentDO;
import cn.iocoder.yudao.module.reading.dal.dataobject.community.CommunityPostDO;
import cn.iocoder.yudao.module.reading.dal.mysql.community.CommunityCommentMapper;
import cn.iocoder.yudao.module.reading.dal.mysql.community.CommunityPostMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import jakarta.annotation.Resource;
import java.time.Duration;
import java.util.Set;

/**
 * 社区计数缓存服务实现类
 *
 * @author 芋道源码
 */
@Service
@Slf4j
public class CommunityCountCacheServiceImpl implements CommunityCountCacheService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource(name = "communityPostMapper")
    private CommunityPostMapper postMapper;

    @Resource
    private CommunityCommentMapper commentMapper;

    // Redis键前缀
    private static final String POST_LIKE_COUNT_KEY = "community:post:like:count:";
    private static final String POST_COMMENT_COUNT_KEY = "community:post:comment:count:";
    private static final String COMMENT_LIKE_COUNT_KEY = "community:comment:like:count:";
    
    // 缓存过期时间：5分钟
    private static final Duration CACHE_EXPIRE_TIME = Duration.ofMinutes(5);

    @Override
    public Long incrementPostLikeCount(Long postId, int increment) {
        String key = POST_LIKE_COUNT_KEY + postId;
        
        // 如果缓存不存在，先从数据库加载
        if (!stringRedisTemplate.hasKey(key)) {
            CommunityPostDO post = postMapper.selectById(postId);
            if (post != null) {
                stringRedisTemplate.opsForValue().set(key, String.valueOf(post.getLikeCount()), CACHE_EXPIRE_TIME);
            }
        }
        
        // 增加计数
        Long newCount = stringRedisTemplate.opsForValue().increment(key, increment);
        stringRedisTemplate.expire(key, CACHE_EXPIRE_TIME);
        
        return newCount;
    }

    @Override
    public Long incrementPostCommentCount(Long postId, int increment) {
        String key = POST_COMMENT_COUNT_KEY + postId;
        
        // 如果缓存不存在，先从数据库加载
        if (!stringRedisTemplate.hasKey(key)) {
            CommunityPostDO post = postMapper.selectById(postId);
            if (post != null) {
                stringRedisTemplate.opsForValue().set(key, String.valueOf(post.getCommentCount()), CACHE_EXPIRE_TIME);
            }
        }
        
        // 增加计数
        Long newCount = stringRedisTemplate.opsForValue().increment(key, increment);
        stringRedisTemplate.expire(key, CACHE_EXPIRE_TIME);
        
        return newCount;
    }

    @Override
    public Long incrementCommentLikeCount(Long commentId, int increment) {
        String key = COMMENT_LIKE_COUNT_KEY + commentId;
        
        // 如果缓存不存在，先从数据库加载
        if (!stringRedisTemplate.hasKey(key)) {
            CommunityCommentDO comment = commentMapper.selectById(commentId);
            if (comment != null) {
                stringRedisTemplate.opsForValue().set(key, String.valueOf(comment.getLikeCount()), CACHE_EXPIRE_TIME);
            }
        }
        
        // 增加计数
        Long newCount = stringRedisTemplate.opsForValue().increment(key, increment);
        stringRedisTemplate.expire(key, CACHE_EXPIRE_TIME);
        
        return newCount;
    }

    @Override
    public Long getPostLikeCount(Long postId) {
        String key = POST_LIKE_COUNT_KEY + postId;
        String countStr = stringRedisTemplate.opsForValue().get(key);
        
        if (countStr != null) {
            return Long.parseLong(countStr);
        }
        
        // 缓存不存在，从数据库获取并缓存
        CommunityPostDO post = postMapper.selectById(postId);
        if (post != null) {
            stringRedisTemplate.opsForValue().set(key, String.valueOf(post.getLikeCount()), CACHE_EXPIRE_TIME);
            return Long.valueOf(post.getLikeCount());
        }
        
        return 0L;
    }

    @Override
    public Long getPostCommentCount(Long postId) {
        String key = POST_COMMENT_COUNT_KEY + postId;
        String countStr = stringRedisTemplate.opsForValue().get(key);
        
        if (countStr != null) {
            return Long.parseLong(countStr);
        }
        
        // 缓存不存在，从数据库获取并缓存
        CommunityPostDO post = postMapper.selectById(postId);
        if (post != null) {
            stringRedisTemplate.opsForValue().set(key, String.valueOf(post.getCommentCount()), CACHE_EXPIRE_TIME);
            return Long.valueOf(post.getCommentCount());
        }
        
        return 0L;
    }

    @Override
    public Long getCommentLikeCount(Long commentId) {
        String key = COMMENT_LIKE_COUNT_KEY + commentId;
        String countStr = stringRedisTemplate.opsForValue().get(key);
        
        if (countStr != null) {
            return Long.parseLong(countStr);
        }
        
        // 缓存不存在，从数据库获取并缓存
        CommunityCommentDO comment = commentMapper.selectById(commentId);
        if (comment != null) {
            stringRedisTemplate.opsForValue().set(key, String.valueOf(comment.getLikeCount()), CACHE_EXPIRE_TIME);
            return Long.valueOf(comment.getLikeCount());
        }
        
        return 0L;
    }

    @Override
    @Scheduled(fixedRate = 300000) // 每5分钟执行一次
    @Transactional(rollbackFor = Exception.class)
    public void syncCountsToDatabase() {
        try {
            // 同步帖子点赞数
            syncPostLikeCounts();
            
            // 同步帖子评论数
            syncPostCommentCounts();
            
            // 同步评论点赞数
            syncCommentLikeCounts();
            
            log.info("[syncCountsToDatabase][计数同步完成]");
            
        } catch (Exception e) {
            log.error("[syncCountsToDatabase][计数同步失败]", e);
        }
    }

    /**
     * 同步帖子点赞数
     */
    private void syncPostLikeCounts() {
        Set<String> keys = stringRedisTemplate.keys(POST_LIKE_COUNT_KEY + "*");
        if (CollUtil.isNotEmpty(keys)) {
            for (String key : keys) {
                try {
                    Long postId = Long.parseLong(key.substring(POST_LIKE_COUNT_KEY.length()));
                    String countStr = stringRedisTemplate.opsForValue().get(key);
                    if (countStr != null) {
                        int newCount = Integer.parseInt(countStr);
                        
                        // 更新数据库
                        CommunityPostDO post = postMapper.selectById(postId);
                        if (post != null && !post.getLikeCount().equals(newCount)) {
                            post.setLikeCount(newCount);
                            postMapper.updateById(post);
                        }
                    }
                } catch (Exception e) {
                    log.warn("[syncPostLikeCounts][同步帖子点赞数失败] key: {}", key, e);
                }
            }
        }
    }

    /**
     * 同步帖子评论数
     */
    private void syncPostCommentCounts() {
        Set<String> keys = stringRedisTemplate.keys(POST_COMMENT_COUNT_KEY + "*");
        if (CollUtil.isNotEmpty(keys)) {
            for (String key : keys) {
                try {
                    Long postId = Long.parseLong(key.substring(POST_COMMENT_COUNT_KEY.length()));
                    String countStr = stringRedisTemplate.opsForValue().get(key);
                    if (countStr != null) {
                        int newCount = Integer.parseInt(countStr);
                        
                        // 更新数据库
                        CommunityPostDO post = postMapper.selectById(postId);
                        if (post != null && !post.getCommentCount().equals(newCount)) {
                            post.setCommentCount(newCount);
                            postMapper.updateById(post);
                        }
                    }
                } catch (Exception e) {
                    log.warn("[syncPostCommentCounts][同步帖子评论数失败] key: {}", key, e);
                }
            }
        }
    }

    /**
     * 同步评论点赞数
     */
    private void syncCommentLikeCounts() {
        Set<String> keys = stringRedisTemplate.keys(COMMENT_LIKE_COUNT_KEY + "*");
        if (CollUtil.isNotEmpty(keys)) {
            for (String key : keys) {
                try {
                    Long commentId = Long.parseLong(key.substring(COMMENT_LIKE_COUNT_KEY.length()));
                    String countStr = stringRedisTemplate.opsForValue().get(key);
                    if (countStr != null) {
                        int newCount = Integer.parseInt(countStr);
                        
                        // 更新数据库
                        CommunityCommentDO comment = commentMapper.selectById(commentId);
                        if (comment != null && !comment.getLikeCount().equals(newCount)) {
                            comment.setLikeCount(newCount);
                            commentMapper.updateById(comment);
                        }
                    }
                } catch (Exception e) {
                    log.warn("[syncCommentLikeCounts][同步评论点赞数失败] key: {}", key, e);
                }
            }
        }
    }

}
